import time
from quant.accounts.order_processing import OrderProcessor
from quant.accounts.api import Api, Spi
from quant.utils import EventEngine
from quant.const import UserEvent
from quant.markets import functions


class Accounts:
    def __init__(self):
        self.all_accounts = []

    def create_account(self, exchange, keys):
        account = Account(exchange, keys)
        self.all_accounts.append(account)
        return account


class Account:
    def __init__(self, exchange, keys):
        from quant.exchanges import get_factory

        factory = get_factory(exchange)
        self.exchange = exchange

        self.balance = {}  # {asset: {'free': 1, 'frozen':2}, ...}
        self.margin = {}   # {symbol: 1, ...}
        self.position = {}  # {s: {'long': l, 'short': s, 'position': p}, ...}
        self.orders = {}

        self.info_engine = AccountInfoEngine()
        self.routing_engine = AccountRoutingEngine()
        self.order_processor = OrderProcessor(self)

        self.api = factory.api_cls(keys, self)
        self.spi = factory.spi_cls(keys, self)

    def add_symbol(self, symbol):
        self.api.add_symbol(symbol)
        self.spi.add_symbol(symbol)

    def subscribe(self, event, callback):
        self.routing_engine.subscribe(event, callback)

    def evaluate(self, balance=True, margin=True):
        value = 0
        if balance:
            for asset, d in self.balance.items():
                factor = functions.get_asset_value(asset)
                if factor is None:
                    factor = 0
                bal = d['free'] + d['frozen']
                value += bal * factor
        if margin:
            for asset, bal in self.margin.items():
                factor = functions.get_asset_value(asset)
                if factor is None:
                    factor = 0
                value += bal * factor
        return value

    def read_order(self, client_id):
        return self.orders.get(client_id, None)

    def read_position(self, symbol):
        if symbol in self.position:
            return self.position[symbol]
        return {'position': 0, 'long': 0, 'short': 0}

    def read_balance(self, asset):
        if asset in self.balance:
            return self.balance[asset]
        return {'free': 0, 'frozen': 0}


class AccountInfoEngine(EventEngine):
    UserData = 'UserData'
    Place = 'Place'
    Cancel = 'Cancel'
    Deal = 'Deal'
    OrderUpdateDetail = 'OrderUpdateDetail'
    OrderUpdateError = 'OrderUpdateError'
    RequestFail = 'RequestFail'
    OperationFail = 'OperationFail'
    SpiStatusInfo = 'SpiStatusInfo'

    def put_place(self, order):
        self.put(self.Place, order)

    def put_cancel(self, order):
        self.put(self.Cancel, order)

    def put_deal(self, order, deal_amount):
        self.put(self.Deal, order, deal_amount)

    def put_order_update_detail(self, order, difference):
        self.put(self.OrderUpdateDetail, order, difference)

    def put_user_data(self, user_data):
        self.put(self.UserData, user_data)

    def put_request_fail(self, api_name, model, response):  # 网络连接失败
        self.put(self.RequestFail, api_name, model, response)

    def put_operation_fail(self, api_name, model, response):
        self.put(self.OperationFail, api_name, model, response)

    def put_order_update_error(self, order_0, order_1, error):
        self.put(self.OrderUpdateError, order_0, order_1, error)

    def put_spi_status_info(self, info):
        self.put(self.SpiStatusInfo, info)

    def show_problems(self):  # ########## test
        def on_fail(api_name, model, response):
            print('request fail {}({}): {}'.format(api_name, model, response.text))
        self.subscribe(self.RequestFail, on_fail)

        def on_error(api_name, model, response):
            print('operation fail {}({}): {}'.format(api_name, model, response.text))
        self.subscribe(self.OperationFail, on_error)

        def on_update_error(order_0, order_1, error):
            print('order update error:', error)
        self.subscribe(self.OrderUpdateError, on_update_error)

    def show_user_data(self):
        def on_ud(ud):
            print('------------{}------------'.format(ud.event))
            print(ud.data)
        self.subscribe(self.UserData, on_ud)
        def on_deal(order, amount):
            print('-----------deal-----------')
            print(order)
            print('deal amount:', amount)
        self.subscribe(self.Deal, on_deal)

    def show_deal(self):
        def on_deal(order, amount):
            print('deal {} {}({}), left({})'.format(order.side, order.price, amount, order.amount))
        self.subscribe(self.Deal, on_deal)


class AccountRoutingEngine(EventEngine):
    def put_user_data(self, user_data):
        self.put(user_data.event, user_data)


if __name__ == '__main__':
    import keys
    account = Account('Binance', keys.get_key('bn_1'))
    # account.api.query_margin('btc/usdt.swap')

    # account.balance['btc'] = {'free': 1, 'frozen': 1}
    # account.position['btc/usdt.swap'] = {'long': 1, 'short': 1, 'position': 0}
    account.margin['btc/usdt.swap'] = 10

    # account.add_symbol('btc/usdt.swap')
    print(account.balance)
    print(account.margin)
    print(account.position)
    input(':')












































